from django.http.response import JsonResponse, HttpResponseForbidden, HttpResponse
from django.shortcuts import render, redirect
from django.contrib.auth.models import User
import hashlib
from user.tasks import send_mail
from user.models import UserInfo, UserScore
from django_redis import get_redis_connection
from django.contrib.auth.hashers import check_password
from django.contrib.auth import  login as auth_login, logout as auth_logout


def register(request):

    if request.method == "GET":
        return render(request, 'register.html')
    # 处理注册逻辑
    # 1.  接收 浏览器 传递的数据
    username = request.POST.get("username")
    password = request.POST.get("password")
    email = request.POST.get("email")

    # 2.  校验手机号 是否已被注册
    #   如果 被注册 、则 提示 该手机号 已被注册
    #  SQL :  select * from auth_user where username = '...' ;
    queryset = User.objects.filter(username=username)

    if queryset.exists():
        return JsonResponse(data={'code': 400, 'message': '该手机号已被注册'})
    #
    # 3. 校验 邮箱 是否 已被 绑定
    # 		 如果 已被 绑定、 则提示 该邮件 已被 其它账号 绑定
    queryset = User.objects.filter(email=email)

    if queryset.exists():
        return JsonResponse(data={'code': 400, 'message': '该邮箱已被绑定'})

    # 4. 将 数据 插入 到 用户 表（账号处于 未激活状态）中 、完成 注册 第一步 。
    # insert into auth_user (username, password, email, is_active) values (..., ..., ..., False);
    user = User.objects.create_user(username=username, password=password, email=email, is_active=False)

    # 生成一个 签名 信息
    message = f"uid={user.pk}&site=www.lovedown.cn"

    sign_text = hashlib.md5(message.encode('utf-8')).hexdigest()
    # 5. 返回成功的JSON数据、并传递 uid 给 页面
    return JsonResponse(data={'code': 200, 'message': '注册成功', 'uid': user.pk, 'sign': sign_text})


def generator_nickname():
    import random
    return "love" +  "".join(random.choices("0123456789", k=6))


def register2(request):

    if request.method == "GET":
        # 接收第一步传递的参数
        user_id = int(request.GET.get("uid"))
        # 获取 签名信息
        sign_text = request.GET.get("sign")

        # 对签名进行校验
        message = f"uid={user_id}&site=www.lovedown.cn"

        if sign_text != hashlib.md5(message.encode('utf-8')).hexdigest():
            return HttpResponseForbidden()

        # 跳转到 注册第二步页面
        return render(request, "register2.html", context={'uid': user_id})

    # 保存用户的基本信息
    user_id = int(request.POST.get("uid"))
    birthday = _post_parameter(request, "birthday")
    nickname = _post_parameter(request, 'nickname', generator_nickname())
    name = _post_parameter(request, "name")
    gender = _post_parameter(request, "gender", "S")

    queryset = UserInfo.objects.filter(user_id=user_id)
    if queryset.exists():
        queryset.update(birthday=birthday, nickname=nickname, name=name, gender=gender)
    else:
        UserInfo.objects.create(user_id=user_id, birthday=birthday, nickname=nickname, name=name, gender=gender)

    redis_client = get_redis_connection()
    redis_key = f"active:{user_id}"
    # 异步发送邮件
    _send_mail(request, user_id, redis_client, redis_key)

    return JsonResponse(data={'code': 200, 'message': '基本信息保存成功', 'nickname': nickname})


def _send_mail(request, user_id, redis_client, redis_key):
    message = f"uid={user_id}&site=www.lovedown.com"
    sign_text = hashlib.md5(message.encode('utf-8')).hexdigest()

    link_url = f"{request.scheme}://{request.get_host()}/active?uid={user_id}&sign={sign_text}"
    # 编写激活邮件模板
    template = f"""
            <p>
                尊敬的用户您好！感谢您注册成为 Lovedown 会员。
            </p>
            <p>
                请点击下面的链接，激活您的账号：
                <a href="{link_url}" target="_blank">
                    {link_url}
                </a>
            </p>
            <p>
                如果以上链接无法点击，请将它复制到浏览器地址栏中打开。
            </p>
            <p>
                该链接1小时内有效，逾期请进行登录、系统会再次发送激活邮件。
            </p>
        """

    user = User.objects.get(pk=user_id)
    # 发送邮件
    send_mail.delay("Lovedown 账号激活", template, user.email)
    # 将 激活连接 存储到 redis 中，并设置过期时间 为 1 小时
    redis_client.setex(redis_key, 3600, sign_text)

def _post_parameter(request, key, default=None):
    val = request.POST.get(key)
    if not val:
        return default
    return val.strip()

def success(request):
    """
    注册成功 用户引导页面
    :param request:
    :return:
    """
    # 添加 referer 头校验、要求该请求 必须添加 referer 头
    if not (referer := request.META.get("HTTP_REFERER", None)) or "/register2" not in referer:
        return HttpResponseForbidden()
    # 获取传入的 昵称
    nickname = request.GET.get("n")
    return render(request, "success.html", context={"nickname": nickname})


def upload_avatar(request):
    """
    上传 头像
    :param request:
    :return:
    """
    avatar = request.FILES.get("avatar")

    uid = int(request.POST.get("uid"))

    if UserInfo.objects.filter(user_id=uid).exists():
        UserInfo.objects.filter(user_id=uid).update(avatar=avatar)
    else:
        # 创建一个 UserInfo 对象
        UserInfo.objects.create(avatar=avatar, user_id=uid)

    return JsonResponse(data={'code': 200, 'message': '上传成功'})


def active_account(request):
    """
    激活账号
    :param request:
    :return:
    """
    # 1. 接收 浏览器 传递的参数 uid 和 sign
    user_id = int(request.GET.get("uid"))
    sign_text = request.GET.get("sign")
    # 2. 进行数字认证
    message = f"uid={user_id}&site=www.lovedown.com"
    if sign_text != hashlib.md5(message.encode('utf-8')).hexdigest():
        return HttpResponseForbidden()

    # 获取当前账号的激活状态
    if User.objects.filter(pk=user_id, is_active=True).exists():
        return HttpResponse("账号已激活，请勿重复激活")
    # 3.获取 redis 连接
    redis_client = get_redis_connection()
    redis_key = f"active:{user_id}"
    if not (val := redis_client.get(redis_key)) or val.decode('utf-8') != sign_text:
        return HttpResponse("激活连接已失效，请重新登录系统，系统会再次发送激活邮件")

    # 4. 如果认证成功、则根据 uid 激活账号
    User.objects.filter(pk=user_id).update(is_active=True)
    # 删除 redis 数据库中的 key
    redis_client.delete(redis_key)

    # 5. 赠送积分
    # 查询积分配置表 中 注册 动作 是否需要赠送积分
    UserScore.objects.create_score("注册", user_id=user_id, remark="用户注册")

    redirect_url = f"{request.scheme}://{request.get_host()}/login"
    # 6. 返回激活成功页面
    return HttpResponse(f'<h1>激活成功、点击进入<a href="{redirect_url}" target="_blank">登录</a>页面</h1>')


def login(request):
    """
    登录
    :param request:
    :return:
    """
    if request.method == "GET":
        # 获取登录成功后要跳转的路由地址，如果没有该参数，默认跳转到系统首页
        next_url = request.GET.get("next", "/")

        return render(request, "login.html", {"next_url": next_url})

    # 接收页面传入的参数
    username = request.POST.get("username")
    password = request.POST.get("password")
    remember = request.POST.get("remember")
    next_url = request.POST.get("nextUrl")
    # 根据用户名 查找 用户是否 已被注册
    queryset = User.objects.filter(username=username)
    if not queryset.exists():
        # 则 提示 用户名 或者密码不正确
        return JsonResponse({"code": 400, "message": "用户名或者密码不正确"})
    # 判断该账号是否激活
    user = queryset.first()
    if not user.is_active:
        # 检查 注册发送的激活邮件是否已经过期、如果没有过期、则 提示用户 尽快激活
        redis_client = get_redis_connection()
        redis_key = f"active:{user.pk}"

        if not redis_client.exists(redis_key):
            # 如果已过期、则重新发送激活邮件
            _send_mail(request, user.pk, redis_client, redis_key)

        return JsonResponse({"code": 400, "message": "激活邮件已发送到邮箱、请尽快激活账号"})

    # 如果该账号已经激活、则比较密码是否一致
    if not check_password(password, user.password):
        return JsonResponse({"code": 400, "message": "用户名或者密码不正确"})
    # 进行登录
    auth_login(request, user)
    # 判断 是否 勾选记住我、如果 没有勾选、则将 session 过期时间 设置为 浏览器关闭即过期
    if remember == "false":
        # 设置 session 过期时间为 浏览器关闭即过期
        request.session.set_expiry(0)
    return JsonResponse({"code": 200, "message": "登录成功", "redirectUrl": next_url})


def email_login(request):
    # 接收页面传入的参数
    email = request.POST.get("email")
    code = request.POST.get("code")
    remember = request.POST.get("remember")
    next_url = request.POST.get("nextUrl")
    # 根据用户名 查找 用户是否 已被注册
    queryset = User.objects.filter(email=email)
    if not queryset.exists():
        # 则 提示 用户名 或者密码不正确
        return JsonResponse({"code": 400, "message": "该邮件未注册"})
    # 判断该账号是否激活
    user = queryset.first()

    redis_client = get_redis_connection()

    if not user.is_active:
        # 检查 注册发送的激活邮件是否已经过期、如果没有过期、则 提示用户 尽快激活
        redis_key = f"active:{user.pk}"

        if not redis_client.exists(redis_key):
            # 如果已过期、则重新发送激活邮件
            _send_mail(request, user.pk, redis_client, redis_key)

        return JsonResponse({"code": 400, "message": "激活邮件已发送到邮箱、请尽快激活账号"})

    # 从 redis 中 获取验证码
    redis_key = f"email:code:{email}"
    redis_code = redis_code.decode('utf-8') if (redis_code := redis_client.get(redis_key)) else None

    if redis_code is None:
        return JsonResponse({"code": 400, "message": "验证码已过期"})
    # 如果该账号已经激活、则比较密码是否一致
    if redis_code != code:
        return JsonResponse({"code": 400, "message": "验证码不正确"})

    # 删除 redis 中存储的 验证码
    redis_client.delete(redis_key)
    # 进行登录
    auth_login(request, user)
    # 判断 是否 勾选记住我、如果 没有勾选、则将 session 过期时间 设置为 浏览器关闭即过期
    if remember == "false":
        # 设置 session 过期时间为 浏览器关闭即过期
        request.session.set_expiry(0)
    return JsonResponse({"code": 200, "message": "登录成功", "redirectUrl": next_url})

def send_email_code(request):
    """
    发送验证码
    """
    # 1. 获取 邮箱
    email = request.POST.get("email")

    # 2. 判断 邮箱 是否存在
    if not User.objects.filter(email=email).exists():
        return JsonResponse({"code": 400, "message": "该邮箱未注册"})

    # 生成验证码
    import random
    code = "".join(random.choices("0123456789", k=6))

    # 设置验证码的过期时间为 5分钟
    redis_client = get_redis_connection()
    redis_key = f"email:code:{email}"
    redis_client.setex(redis_key, 300, code)
    # 发送邮件
    send_mail("Lovedown 邮箱验证码", f"您的验证码为：{code}，5分钟内有效，请尽快使用", email)

    # 返回结果
    return JsonResponse({"code": 200, "message": "验证码已发送"})


def logout(request):
    auth_logout(request)
    return redirect(to="login")

def index(request):

    return render(request, "index.html")